﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using SpringGraph.Extensions;
using System.Windows.Threading;

namespace SpringGraph.Controls
{
    [TemplatePart(Name = "spin", Type = typeof(Button))]
    [TemplatePart(Name = "up", Type = typeof(Button))]
    [TemplatePart(Name = "down", Type = typeof(Button))]
    [TemplatePart(Name = "left", Type = typeof(Button))]
    [TemplatePart(Name = "right", Type = typeof(Button))]
    [TemplatePart(Name = "zoomIn", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "zoomOut", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "repIn", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "repOut", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "rotationGlobeGrid", Type = typeof(Grid))]
    [TemplatePart(Name = "repulsionSlider", Type = typeof(Slider))]
    [TemplatePart(Name = "zoomSlider", Type = typeof(Slider))]
    public class NavControl : Control
    {
        private SpringGraph _SpringGraph
        {
            get
            {
                return this.ParentOfType<SpringGraph>();
            }
        }

        private VisualState _CollapseNavigation;
        private VisualState _ExpandNavigation;
        private Border _ToolbarBorder;
        private Button down;

        //Variables to preserve map location during rotation.
        private Button left;
        private Button right;
        private Button spin;
        private Button up;
        private RepeatButton zoomIn;
        private RepeatButton zoomOut;
        private RepeatButton repIn;
        private RepeatButton repOut;
        private Slider repulsionSlider;
        private Slider zoomSlider;

        private bool templateApplied = false;

        public static readonly DependencyProperty ExpandOnLoadProperty = DependencyProperty.Register(
           "ExpandOnLoad", typeof(bool), typeof(NavControl), new PropertyMetadata(true));
        public bool ExpandOnLoad
        {
            get
            {
                return (bool)this.GetValue(ExpandOnLoadProperty);
            }
            set
            {
                this.SetValue(ExpandOnLoadProperty, value);
            }
        }

        public static readonly DependencyProperty ExpandOnLoadDelayProperty = DependencyProperty.Register(
           "ExpandOnLoadDelay", typeof(double), typeof(NavControl), new PropertyMetadata(1.0));
        public double ExpandOnLoadDelay
        {
            get
            {
                return (double)this.GetValue(ExpandOnLoadDelayProperty);
            }
            set
            {
                this.SetValue(ExpandOnLoadDelayProperty, value);
            }
        }

        public static readonly DependencyProperty InvertedMovementProperty = DependencyProperty.Register(
           "InvertedMovement", typeof(bool), typeof(NavControl), new PropertyMetadata(true));
        public bool InvertedMovement
        {
            get
            {
                return (bool)this.GetValue(InvertedMovementProperty);
            }
            set
            {
                this.SetValue(InvertedMovementProperty, value);
            }
        }

        /// <summary>
        /// NavControl Constructor, will use the default instance of the map
        /// </summary>
        public NavControl() 
        {
            DefaultStyleKey = typeof(NavControl);
        }


        

        /// <summary>
        /// Overrides the default OnApplyTemplate to configure child FrameworkElement references from the applied template
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            spin = (Button)GetTemplateChild("spin");
            up = (Button)GetTemplateChild("up");
            down = (Button)GetTemplateChild("down");
            left = (Button)GetTemplateChild("left");
            right = (Button)GetTemplateChild("right");
            zoomIn = (RepeatButton)GetTemplateChild("zoomIn");
            zoomOut = (RepeatButton)GetTemplateChild("zoomOut");
            repIn = (RepeatButton)GetTemplateChild("repIn");
            repOut = (RepeatButton)GetTemplateChild("repOut");
            repulsionSlider = (Slider)GetTemplateChild("repulsionSlider");
            zoomSlider = (Slider)GetTemplateChild("zoomSlider");


            _ExpandNavigation = (VisualState)GetTemplateChild("Expanded");
            _CollapseNavigation = (VisualState)GetTemplateChild("Collapsed");


            _ToolbarBorder = (Border)GetTemplateChild("borderNavigation");


            spin.Click += spin_Click;
            zoomIn.Click += zoomIn_Click;
            zoomOut.Click += zoomOut_Click;

            up.Click += up_Click;
            down.Click += down_Click;
            left.Click += left_Click;
            right.Click += right_Click;

            repIn.Click += new RoutedEventHandler(repIn_Click);
            repOut.Click += new RoutedEventHandler(repOut_Click);

            if (_SpringGraph != null)
            {
                repulsionSlider.Value = _SpringGraph.RepulsionFactor;
                zoomSlider.Value = _SpringGraph.Scale;

                repulsionSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(repulsionSlider_ValueChanged);
                _SpringGraph.RepulsionFactorChanged += new EventHandler<EventArgs>(_SpringGraph_RepulsionFactorChanged);

                zoomSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(zoomSlider_ValueChanged);
                _SpringGraph.ScaleChanged += new EventHandler<EventArgs>(_SpringGraph_ScaleChanged);
            }

            if (!Expanded)
            {
                VisualStateManager.GoToState(this, "Collapsed", false);
            }

            templateApplied = true;

            CheckExpand();
        }

        public void CheckExpand()
        {
            if (expandTimer != null && expandTimer.IsEnabled)
                expandTimer.Stop();

            if (ExpandOnLoad)
            {
                if (!_SpringGraph.IsBusy)
                    DoExpandOnLoad();
                else
                    _SpringGraph.LoadCompleted += new EventHandler<EventArgs>(_SpringGraph_LoadCompleted);
            }
        }

        void _SpringGraph_LoadCompleted(object sender, EventArgs e)
        {
            DoExpandOnLoad();
        }

        DispatcherTimer expandTimer;

        private void DoExpandOnLoad()
        {
            expandTimer = new DispatcherTimer();
            expandTimer.Interval = TimeSpan.FromSeconds(ExpandOnLoadDelay);
            expandTimer.Tick += new EventHandler(expandTimer_Tick);
            expandTimer.Start();
        }

        void expandTimer_Tick(object sender, EventArgs e)
        {
            var timer = sender as DispatcherTimer;
            timer.Stop();

            Expanded = true;
        }

        void _SpringGraph_ScaleChanged(object sender, EventArgs e)
        {
            zoomSlider.Value = _SpringGraph.Scale;
        }

        void zoomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            _SpringGraph.Scale = zoomSlider.Value;
        }

        void _SpringGraph_RepulsionFactorChanged(object sender, EventArgs e)
        {
            repulsionSlider.Value = _SpringGraph.RepulsionFactor;
        }

        void repulsionSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            _SpringGraph.RepulsionFactor = repulsionSlider.Value;
        }

        public static readonly DependencyProperty ExpandedProperty = DependencyProperty.Register(
            "Expanded", typeof(bool), typeof(NavControl), new PropertyMetadata(false, ExpandedPropertyChanged));

        private static void ExpandedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var navControl = sender as NavControl;

            if (navControl.zoomIn != null)
            {
                if (!navControl.Expanded)
                {
                    VisualStateManager.GoToState(navControl, "Collapsed", navControl.templateApplied);
                }
                else
                {
                    VisualStateManager.GoToState(navControl, "Expanded", navControl.templateApplied);
                }
            }
        }

        public bool Expanded
        {
            get
            {
                return (bool)this.GetValue(ExpandedProperty);
            }
            set
            {
                if (Expanded != value)
                {
                    this.SetValue(ExpandedProperty, value);
                }
            }
        }

        private void spin_Click(object sender, RoutedEventArgs e)
        {
            Expanded = !Expanded;
        }

        private double _IncMove = 10;

        private void up_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.Scroll(0, InvertedMovement ? _IncMove : -_IncMove);
        }

        private void down_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.Scroll(0, InvertedMovement ? -_IncMove : _IncMove);
        }

        private void left_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.Scroll(InvertedMovement ? _IncMove : -_IncMove, 0);
        }

        private void right_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.Scroll(InvertedMovement ? -_IncMove : _IncMove, 0);
        }

        private double _IncZoom = 0.1;

        private void zoomIn_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.Scale += _IncZoom;
        }

        private void zoomOut_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.Scale -= _IncZoom;
        }

        private double _IncRep = 0.05;

        void repOut_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.RepulsionFactor -= _IncRep;
        }

        void repIn_Click(object sender, RoutedEventArgs e)
        {
            _SpringGraph.RepulsionFactor += _IncRep;
        }

    }
}
